


#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <windows.h>



#define XTE_USE_LITE
#define XTE_USE_FULL
#define XTE_USE_MAKE



#include "json.h"
#include "xtemplate.h"
#include "xtemplate_json.h"



// 读取失败返回 NULL，返回值不再使用时应调用 free 释放
char* File_ReadAll(char* sPath)
{
	FILE *fp = fopen(sPath, "r");
	if ( fp == NULL ) {
		return NULL;
	}
	fseek(fp, 0, SEEK_END);
	size_t iSize = ftell(fp);
	fseek(fp, 0, SEEK_SET);
	char* sRet = malloc(iSize + 1);
	if ( sRet == NULL ) {
		fclose(fp);
		return NULL;
	}
	fread(sRet, iSize, 1, fp);
	int bRet = ferror(fp);
	fclose(fp);
	if ( bRet ) {
		free(sRet);
		return NULL;
	} else {
		sRet[iSize] = 0;
		return sRet;
	}
}



// 输出 Token 信息
void PrintTokenInfo(int idx, XTE_TokenItem objTok, char* sText)
{
	if ( objTok->Type == XTE_TK_TEXT ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_TEXT (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_COMMEN ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_COMMEN (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_VAR ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_VAR (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_NUM ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_NUM (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_TIME ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_TIME (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_BOOL ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_BOOL (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_ARR ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_ARR (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_PROC ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_PROC (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_SUBTEMPLATE ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_SUBTEMPLATE (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_INCLUDE ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_INCLUDE (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_DEFINE ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_DEFINE (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_SCRIPT ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_SCRIPT (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_IF ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_IF (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_ELSEIF ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_ELSEIF (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_ELSE ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_ELSE (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_FOR ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_FOR (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_FOREACH ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_FOREACH (%d)\n", idx, objTok->Type);
	} else if ( objTok->Type == XTE_TK_END ) {
		printf("\t★★★ Token Type [%d] : XTE_TK_END (%d)\n", idx, objTok->Type);
	} else {
		printf("\t★★★ Error : Unknown Token Type ID [%d] : %d\n", idx, objTok->Type);
	}
	printf("\t* Line : %d\n", objTok->RefLine);
	printf("\t* LinePos : %d\n", objTok->RefLinePos);
	printf("\t* Pos : %d\n", objTok->RefPos);
	printf("\t* Lehgth : %d\n", objTok->RefSize);
	if ( objTok->ParamCount > 0 ) {
		for ( int iPos = 0; iPos < objTok->ParamCount; iPos++ ) {
			printf("\t* Param [%d] (%d) : \"%s\"\n", iPos, objTok->ParamSize[iPos], objTok->ParamText[iPos]);
		}
	}
	printf("\t* Content Text (+Ref Content Text) :\n\t------------------------------------\n%s\n\t------------------------------------\n", objTok->Text);
	printf("%.*s\n\t------------------------------------\n\n\n", objTok->RefSize, &sText[objTok->RefPos - 1]);
}



// 输出子模板信息
int PrintSubTemplateInfo(Hash32_Key* pKey, PAMM_Object objAction, void* pArg)
{
	printf("SubTemplate - %s :\n", pKey->Key);
	for ( int i = 1; i <= objAction->Count; i++ ) {
		XTE_TokenItem objTok = (XTE_TokenItem)PAMM_GetVal_Unsafe(objAction, i);
		// 输出 Token 信息
		PrintTokenInfo(i, objTok, pArg);
	}
	return 0;
}



// Lexer 测试
void TestLexer()
{
	XTE_IdentList objList = xteCreateIdentList();
	xteAddIdentToList(objList, "end"		, 3, XTE_TK_END		, XTE_IDTPE_DEFAULT	, 0, 0);
	xteAddIdentToList(objList, "include"	, 7, XTE_TK_INCLUDE	, XTE_IDTPE_DEFAULT	, 1, 1);
	xteAddIdentToList(objList, "define"		, 6, XTE_TK_DEFINE	, XTE_IDTPE_DEFAULT	, 1, 1);
	xteAddIdentToList(objList, "script"		, 6, XTE_TK_SCRIPT	, XTE_IDTPE_BLOCK	, 1, 1);
	xteAddIdentToList(objList, "if"			, 2, XTE_TK_IF		, XTE_IDTPE_DEFAULT	, 1, 1);
	xteAddIdentToList(objList, "elseif"		, 6, XTE_TK_ELSEIF	, XTE_IDTPE_DEFAULT	, 1, 1);
	xteAddIdentToList(objList, "else"		, 4, XTE_TK_ELSE	, XTE_IDTPE_DEFAULT	, 0, 0);
	xteAddIdentToList(objList, "for"		, 3, XTE_TK_FOR		, XTE_IDTPE_DEFAULT	, 2, 3);
	xteAddIdentToList(objList, "foreach"	, 7, XTE_TK_FOREACH	, XTE_IDTPE_DEFAULT	, 1, 1);
	
	char* sRet = File_ReadAll("test_xte.txt");
	XTE_TokenList objToks = xteLexer(sRet, 0, objList, NULL);
	if ( objToks->Success ) {
		printf("test_xte.txt Lexer success !\n");
		printf("\tToken Count : %d\n\n\n", objToks->Tokens.Count);
		for ( int i = 1; i <= objToks->Tokens.Count; i++ ) {
			XTE_TokenItem objTok = SAMM_GetPtr_Unsafe(&objToks->Tokens, i);
			// 输出 Token 信息
			PrintTokenInfo(i, objTok, sRet);
		}
	} else {
		printf("test_xte.txt Lexer failed !\n");
		printf("Error : %s\n", objToks->ErrorDesc);
		printf("Error Info : Line : %d\n", objToks->ErrorLine);
		printf("Error Info : LinePos : %d\n", objToks->ErrorLinePos);
		printf("Error Info : Pos : %d\n", objToks->ErrorPos);
		printf("Error Info : RefLine : %d\n", objToks->ErrorRefLine);
		printf("Error Info : RefLinePos : %d\n", objToks->ErrorRefLinePos);
		printf("Error Info : RefPos : %d [%.10s]\n", objToks->ErrorRefPos, &sRet[objToks->ErrorRefPos]);
	}
	xteLexerFree(objToks);
}



// TinyParse 测试
void TestTinyParse()
{
	char* sRet = File_ReadAll("test_lite.txt");
	XTE_LiteObject objTemplate = xteLiteParse(sRet, 0, NULL);
	if ( objTemplate->Success ) {
		printf("test_lite.txt Parse success !\n");
		printf("\tToken Count : %d\n", objTemplate->Tokens->Count);
		printf("\tAction Count : %d\n", objTemplate->Actions.Count);
		printf("\tSubTemplate Count : %d\n\n\n", AVLHT32_Count(&objTemplate->SubTemplates));
		printf("Actions :\n");
		for ( int i = 1; i <= objTemplate->Actions.Count; i++ ) {
			XTE_TokenItem objTok = (XTE_TokenItem)PAMM_GetVal_Unsafe(&objTemplate->Actions, i);
			// 输出 Token 信息
			PrintTokenInfo(i, objTok, sRet);
		}
		// 遍历输出子模板信息：
		AVLHT32_Walk(&objTemplate->SubTemplates, (void*)PrintSubTemplateInfo, sRet);
	} else {
		printf("test_lite.txt Parse failed !\n");
		printf("Error : %s\n", objTemplate->ErrorDesc);
		printf("Error Info : Line : %d\n", objTemplate->ErrorLine);
		printf("Error Info : LinePos : %d\n", objTemplate->ErrorLinePos);
		printf("Error Info : Pos : %d\n", objTemplate->ErrorPos);
		printf("Error Info : RefLine : %d\n", objTemplate->ErrorRefLine);
		printf("Error Info : RefLinePos : %d\n", objTemplate->ErrorRefLinePos);
		printf("Error Info : RefPos : %d [%.10s]\n", objTemplate->ErrorRefPos, &sRet[objTemplate->ErrorRefPos]);
	}
	xteLiteParseFree(objTemplate);
}



// Parse 测试
void TestParse()
{
}



int main()
{
	SetConsoleOutputCP(65001);
	printf("TestMode :\n");
	
	//TestLexer();
	//TestTinyParse();
	//TestParse();
	
	printf("TestMode End\n");
	return 0;
}


